import requests
import hashlib
import base64
import os
from typing import Dict, Any, Optional
from pathlib import Path


class GhostCutUploader:
    """
    GhostCut API 上传工具类
    用于获取上传凭证、上传文件和删除文件
    """

    def __init__(self, app_key: str, app_secret: str):
        """
        初始化GhostCut上传工具
        
        Args:
            app_key (str): GhostCut平台的AppKey
            app_secret (str): GhostCut平台的AppSecret
        """
        self.app_key = app_key
        self.app_secret = app_secret
        self.base_url = "https://api.zhaoli.com/v-w-c/gateway/ve/file"

    def _generate_signature(self, body: str) -> str:
        """
        生成API签名
        
        Args:
            body (str): 请求体的JSON字符串
            
        Returns:
            str: 签名字符串
        """
        md5_body = hashlib.md5(body.encode('utf-8')).hexdigest()
        sign_string = md5_body + self.app_secret
        signature = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
        return signature

    def get_upload_policy(self, nonce: str, material_file_type: str = "image", 
                         expire_seconds: Optional[int] = None, 
                         id_series: Optional[str] = None,
                         material_name: Optional[str] = None) -> Dict[str, Any]:
        """
        获取上传凭证
        
        Args:
            nonce (str): 随机字符串
            material_file_type (str): 文件类型，可选值: "image", "video", "srt", "video_series"
            expire_seconds (int, optional): 签名凭证过期时间(秒)，范围1~86400，默认3600
            id_series (str, optional): 剧所在项目的id（当material_file_type为video_series时必需）
            material_name (str, optional): 素材名称
            
        Returns:
            dict: 包含上传凭证信息的字典
        """
        url = f"{self.base_url}/upload/policy/apply"
        
        # 构造请求参数
        payload = {
            "nonce": nonce,
            "materialFileType": material_file_type
        }
        
        if expire_seconds:
            payload["expireSeconds"] = expire_seconds
            
        if id_series:
            payload["idSeries"] = id_series
            
        if material_name:
            payload["materialName"] = material_name
        
        # 转换为JSON字符串
        body = str(payload).replace("'", '"')  # 简单转换为JSON格式
        
        # 生成签名
        signature = self._generate_signature(body)
        
        # 设置请求头
        headers = {
            "Content-Type": "application/json",
            "AppKey": self.app_key,
            "AppSign": signature
        }
        
        # 发送请求
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        
        result = response.json()
        if result.get("code") != 1000:
            raise Exception(f"获取上传凭证失败: {result.get('msg')}")
            
        return result["body"]

    def upload_file(self, policy: Dict[str, Any], file_path: str, file_name: Optional[str] = None) -> str:
        """
        使用上传凭证上传文件
        
        Args:
            policy (dict): get_upload_policy方法返回的上传凭证
            file_path (str): 本地文件路径
            file_name (str, optional): 上传后的文件名，如果不指定则使用原文件名
            
        Returns:
            str: 上传成功的文件URL
        """
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        # 获取文件名
        if not file_name:
            file_name = Path(file_path).name
            
        # 构造上传参数
        files = {
            "key": (None, policy["dir"] + file_name),
            "OSSAccessKeyId": (None, policy["accessid"]),
            "policy": (None, policy["policy"]),
            "signature": (None, policy["signature"]),
            "callback": (None, policy["base64CallbackBody"]),
            "success_action_status": (None, "200"),
            "file": (file_name, open(file_path, "rb"))
        }
        
        try:
            # 上传文件
            response = requests.post(policy["host"], files=files)
            response.raise_for_status()
            
            result = response.json()
            if result.get("Status") != "OK":
                raise Exception(f"文件上传失败: {response.text}")
                
            # 返回文件URL
            return policy["urlPrefix"] + file_name
        finally:
            # 关闭文件
            files["file"][1].close()

    def delete_file(self, file_key: str) -> int:
        """
        删除已上传的文件
        
        Args:
            file_key (str): 文件的key（上传接口中的key字段）
            
        Returns:
            int: 成功删除的文件数量
        """
        url = f"{self.base_url}/remove"
        
        # 构造请求参数
        payload = {
            "key": file_key
        }
        
        # 转换为JSON字符串
        body = str(payload).replace("'", '"')
        
        # 生成签名
        signature = self._generate_signature(body)
        
        # 设置请求头
        headers = {
            "Content-Type": "application/json",
            "AppKey": self.app_key,
            "AppSign": signature
        }
        
        # 发送请求
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        
        result = response.json()
        if result.get("code") != 1000:
            raise Exception(f"删除文件失败: {result.get('msg')}")
            
        return result["body"]

    def upload_file_simple(self, file_path: str, material_file_type: str = "image", 
                          file_name: Optional[str] = None) -> str:
        """
        简化版文件上传方法，一键获取凭证并上传文件
        
        Args:
            file_path (str): 本地文件路径
            material_file_type (str): 文件类型，可选值: "image", "video", "srt"
            file_name (str, optional): 上传后的文件名，如果不指定则使用原文件名
            
        Returns:
            str: 上传成功的文件URL
        """
        # 生成随机nonce
        import time
        nonce = f"nonce_{int(time.time())}"
        
        # 获取上传凭证
        policy = self.get_upload_policy(nonce, material_file_type)
        
        # 上传文件
        url = self.upload_file(policy, file_path, file_name)
        
        return url


def demo():
    """
    使用示例
    """
    # 初始化上传器
    uploader = GhostCutUploader("your_app_key", "your_app_secret")
    
    try:
        # 方法1: 分步上传
        # 1. 获取上传凭证
        policy = uploader.get_upload_policy("random_nonce_string", "image")
        
        # 2. 上传文件
        file_url = uploader.upload_file(policy, "/path/to/your/file.jpg", "test.jpg")
        print(f"文件上传成功，URL: {file_url}")
        
        # 方法2: 一键上传
        file_url = uploader.upload_file_simple("/path/to/your/file.jpg", "image", "test2.jpg")
        print(f"文件上传成功，URL: {file_url}")
        
        # 删除文件示例（谨慎使用）
        # 注意：这会真正删除文件，不只是记录
        # delete_count = uploader.delete_file("ve_material_image2/A-xxx/xxx/test.jpg")
        # print(f"成功删除 {delete_count} 个文件")
        
    except Exception as e:
        print(f"操作失败: {e}")


if __name__ == "__main__":
    demo()